<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

    

    <title>SpringBoot系统日志设计及实现方案 | 竹隐江南的博客</title>
    <meta name="author" content="dzy20@qq.com">
    
    <meta name="description" content="SpringBoot系统日志设计及实现方案">
    
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <meta property="og:title" content="SpringBoot系统日志设计及实现方案"/>
    <meta property="og:site_name" content="必须有人浴血奋战，世上才有自由可言！"/>

    
    <meta property="og:image" content="undefined"/>
    

    <link rel="icon" type="image/png" href="/favicon.png">
    <link rel="alternate" href="/atom.xml" title="必须有人浴血奋战，世上才有自由可言！" type="application/atom+xml">
    <link rel="stylesheet" href="/css/lib/materialize.min.css">
    <link rel="stylesheet" href="/css/lib/font-awesome.min.css">
    <link rel="stylesheet" href="/css/style.css" media="screen" type="text/css">

    
        <link rel="stylesheet" href="/css/lib/prettify-tomorrow-night-eighties.css" type="text/css">
    
    <!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
</head>


<body>
    <img src="/weixin_favicon.png" style="position: absolute; left: -9999px; opacity: 0; filter: alpha(opacity=0);">

    <nav class="green">
    <div class="nav-wrapper">
        <a href="#" data-activates="main-menu" class="button-collapse">
            <i class="fa fa-navicon"></i>
        </a>
        <div class="">
            <a href="/" class="brand-logo hide-on-med-and-down">必须有人浴血奋战，世上才有自由可言！</a>
            <ul class="right hide-on-med-and-down">
                
                    <li>
                        <a class="menu-home " href="/" >
                            <i class="fa fa-home "></i>
                            
                            首页
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-archive " href="/archives" >
                            <i class="fa fa-archive "></i>
                            
                            归档
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-category category-menu" href="javascript:;" data-activates="category-menu" >
                            <i class="fa fa-bookmark "></i>
                            
                            分类
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-reading " href="/reading" >
                            <i class="fa fa-book "></i>
                            
                            读书
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-about " href="/about" >
                            <i class="fa fa-user "></i>
                            
                            关于
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-search modal-trigger " href="#search" >
                            <i class="fa fa-search "></i>
                            
                            搜索
                        </a>
                    </li>
                
            </ul>
            <div>
    <ul class="side-nav green darken-1" id="main-menu">
        
        <li class="side-user">
            <div class="row">
                <div class="col s4 no-padding">
                    <img class="avatar-image circle responsive-img" src="https://static.oschina.net/uploads/user/728/1456911_100.jpg?t=1393495702000" alt="User Avatar">
                </div>
                <div class="info col s8 valign-wrapper no-padding">
                    <div class="valign">
                        <p class="name">竹隐江南</p>
                        <p class="desc">Java后端/技术宅</p>
                    </div>
                </div>
            </div>
        </li>
        

        
            <li class="no-padding">
                <a class="waves-effect menu-home " href="/" >
                    <i class="fa fa-home "></i>
                    
                    首页
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-archive " href="/archives" >
                    <i class="fa fa-archive "></i>
                    
                    归档
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-category category-menu" href="javascript:;" data-activates="category-menu" >
                    <i class="fa fa-bookmark "></i>
                    
                    分类
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-reading " href="/reading" >
                    <i class="fa fa-book "></i>
                    
                    读书
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-about " href="/about" >
                    <i class="fa fa-user "></i>
                    
                    关于
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-search modal-trigger " href="#search" >
                    <i class="fa fa-search "></i>
                    
                    搜索
                </a>
            </li>
        
    </ul>

    <ul class="side-nav green darken-1" id="category-menu">
    

            

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/hive/">
                    hive <span class="right">2 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/Docker/">
                    Docker <span class="right">10 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/操作系统/">
                    操作系统 <span class="right">7 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/系统架构/">
                    系统架构 <span class="right">2 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/DevOps-CI/">
                    DevOps-CI <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/SSL/">
                    SSL <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/springboot/">
                    springboot <span class="right">8 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/Linux/">
                    Linux <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-1" collapse-level="1">
                <a class="no-padding" href="/categories/Linux/Tomcat/">
                    Tomcat <span class="right">1 篇</span></a>
                </a>
            </li>

        

    </ul>
</div>

        </div>
    </div>
</nav>

<div id="search" class="modal search-modal">
    <div class="row">
        <div class="input-field col s12">
              <input id="search-input" type="text">
              <label for="search-input">搜索</label>
        </div>

    </div>
    <div id="search-result" class="search-result col s12">

    </div>
</div>


    <main>
        <div class="container main-container">
    <nav class="page-nav hide-on-small-only">
    <div class="nav-wrapper green">
        <span class="breadcrumb">当前位置（分类目录）</span>
        
            
    
    
    <a class="breadcrumb" href="/categories/springboot/">springboot</a>


        

        
    </div>
</nav>

<article>
    <div class="card">
        <div class="card-content">
            

            <div class="article-title">
                
    
        <h1>SpringBoot系统日志设计及实现方案</h1>
    


            </div>
            <time class="red-link-context" datetime="2017-07-06T05:56:00.000Z"><a href="/2017/07/06/SpringBoot系统日志设计及实现方案/">2017-07-06</a></time>

            <span id="busuanzi_container_page_pv" class="read-times-container">
    <i class="fa fa-eye"></i>
    <span id="busuanzi_value_page_pv"></span>
</span>

            
    <div class="tags-row">
        
            <a href="/tags/springboot/" class="chip red lighten-1">springboot</a>
        
    </div>


            <div class="toc red-link-context hide-on-med-and-down">
    <ol class="section table-of-contents"><li class="section table-of-contents-item section table-of-contents-level-1"><a class="section table-of-contents-link" href="#设计方案及原因"><span class="section table-of-contents-text">设计方案及原因</span></a></li><li class="section table-of-contents-item section table-of-contents-level-1"><a class="section table-of-contents-link" href="#修改Logback日志记录格式"><span class="section table-of-contents-text">修改Logback日志记录格式</span></a></li><li class="section table-of-contents-item section table-of-contents-level-1"><a class="section table-of-contents-link" href="#Web请求日志记录，日志记录串"><span class="section table-of-contents-text">Web请求日志记录，日志记录串</span></a></li></ol>
</div>


            <div class="entry red-link-context">
                <h1 id="设计方案及原因"><a href="#设计方案及原因" class="headerlink" title="设计方案及原因"></a>设计方案及原因</h1><p>一个庞大的系统，或者一个访问量高的系统，在发生异常的时候，大家定位问题是怎么定位的呢？要求5分钟之内知道问题引起的原因并给出初步结论？多台服务器通过F5分发的情况下呢？</p>
<p>其实大家都是去看日志，不过很多人用的都是默认日志记录，最多是日志里记录了执行sql，虽然SpringBoot的本身日志很详细了，但是定位不快速，要想快速定位需要一个请求串号，我需要知道这个请求串号唯一标识，直接找到这个串号范围之内的日志内容，这比你打开10MB，30MB里面寻找快多了吧。</p>
<a id="more"></a>
<h1 id="修改Logback日志记录格式"><a href="#修改Logback日志记录格式" class="headerlink" title="修改Logback日志记录格式"></a>修改Logback日志记录格式</h1><p>先看一下上一节的日志输出格式，如下，使用的是PatternLayoutEncoder这个类，</p>
<pre><code>&lt;encoder class=&quot;ch.qos.logback.classic.encoder.PatternLayoutEncoder&quot;&gt;
    &lt;!--格式化输出：%d表示日期，%thread表示线程名，%-5level：级别从左显示5个字符宽度%msg：日志消息，%n是换行符--&gt;
    &lt;pattern&gt;%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n&lt;/pattern&gt;
&lt;/encoder&gt;
</code></pre><p>PatternLayoutEncoder类里面用了PatternLayout这个类，这个类里面就是声明的格式字符串，</p>
<pre><code>public class PatternLayoutEncoder extends PatternLayoutEncoderBase&lt;ILoggingEvent&gt; {
    public PatternLayoutEncoder() {
    }

    public void start() {
        PatternLayout patternLayout = new PatternLayout();
        patternLayout.setContext(this.context);
        patternLayout.setPattern(this.getPattern());
        patternLayout.setOutputPatternAsHeader(this.outputPatternAsHeader);
        patternLayout.start();
        this.layout = patternLayout;
        super.start();
    }
}
</code></pre><p>PatternLayout类里面的格式</p>
<pre><code>public class PatternLayout extends PatternLayoutBase&lt;ILoggingEvent&gt; {
    public static final Map&lt;String, String&gt; defaultConverterMap = new HashMap();
    public static final String HEADER_PREFIX = &quot;#logback.classic pattern: &quot;;

    static {
        defaultConverterMap.putAll(Parser.DEFAULT_COMPOSITE_CONVERTER_MAP);
        defaultConverterMap.put(&quot;d&quot;, DateConverter.class.getName());
        defaultConverterMap.put(&quot;date&quot;, DateConverter.class.getName());
        defaultConverterMap.put(&quot;r&quot;, RelativeTimeConverter.class.getName());
        defaultConverterMap.put(&quot;relative&quot;, RelativeTimeConverter.class.getName());
        defaultConverterMap.put(&quot;level&quot;, LevelConverter.class.getName());
        ....
</code></pre><p>那我们来建立一个格式化的类，IpConverter，这个类用来记录是那台服务器IP及机器名产生的日志。</p>
<pre><code>/**
 * [@ClassName](https://my.oschina.net/u/3112573): BussinesLogger
 * @Description: 业务日志记录类
 * [@author](https://my.oschina.net/arthor) dengzongyu
 * [@date](https://my.oschina.net/u/2504391) 2016年12月5日 下午4:29:48
 *
 */
public class IpConverter extends ClassicConverter {

    /**
     * 业务系统机器名称
     */
    private static String hostName = &quot;&quot;;

    /**
     * 业务系统机器的IP
     */
    private static String hostIp = &quot;&quot;;

    static {
        InetAddress ia = null;
        try {
            ia = InetAddress.getLocalHost();
            hostIp = ia.getHostAddress();
            hostName = ia.getHostName();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public String convert(ILoggingEvent event) {
        return new StringBuilder(hostIp).append(&quot;:&quot;).append(hostName).toString();
    }

}
</code></pre><p>然后写一个类集成我们上面提到的PatternLayout类，用来注入日志记录格式，格式多了个ip。</p>
<pre><code>/**
 * @ClassName: GAPatternlayout
 * @Description: Logback配置文件注入
 * @author dengzongyu
 * @date 2016年12月5日 下午5:07:18
 *
 */
public class GAPatternlayout extends PatternLayout {

    static{
        defaultConverterMap.put(&quot;ip&quot;, IpConverter.class.getName());
    }

}
</code></pre><p>接下来修改logback-spring.xml配置文件，修改的位置就是修改那两个格式输出的位置，类改为我们自己写的，这样子输出出来的格式就是：服务器IP:服务器名字：日期，线程名，级别从左显示5个字符宽度：日志消息等…现在我们日志里面容易定位出是哪台服务器产生的异常了。</p>
<pre><code>&lt;layout class=&quot;jldp.portal.framework.logback.GAPatternlayout&quot;&gt;
    &lt;Pattern&gt;%ip:%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -- %msg
        %n
    &lt;/Pattern&gt;
&lt;/layout&gt;
</code></pre><h1 id="Web请求日志记录，日志记录串"><a href="#Web请求日志记录，日志记录串" class="headerlink" title="Web请求日志记录，日志记录串"></a>Web请求日志记录，日志记录串</h1><p>上面那些基本够用了，但是我们想更细致一些，比如用户是请求哪个API接口，请求参数是什么，请求接口响应时间等等….<br>这个讲解都在代码注释里面了，上面就不重复了，直接上代码。里面有个IPUtil这个是就是获取客户端IP的工具类，网上一大堆，就不贴了，各位根据自己的需要来，这个是我自己写的，我觉得够了，你们可以设计的更加完美一些，为了将来大数据分析考虑，写成JSON格式的更好是不。</p>
<pre><code>/**
 * @ClassName: WebRequestLogRecording
 * @Description: Web请求日志记录
 * @author dengzongyu
 * @date 2016年12月6日 下午3:40:25
 *
 */
@Aspect
@Component
@Order(-5)
public class WebRequestLogRecording {

    private static Logger logger = LoggerFactory.getLogger(WebRequestLogRecording.class);

    /**
     * 每次请求的串
     */
    private ThreadLocal&lt;String&gt; requestUUID = new ThreadLocal&lt;String&gt;();

    private ThreadLocal&lt;Long&gt; startTime = new ThreadLocal&lt;Long&gt;();

    /**
     * 
     * WebRequestLog: 定义拦截点
     * @author dengzongyu
     * @since JDK 1.8
     */
    @Pointcut(&quot;execution(public * com.dengzy..controller..*.*(..))&quot;)
    public void webRequestLog(){}

    /**
     * 
     * doBefore:进入切入点前进行操作.
     *
     * @author dengzongyu
     * @since JDK 1.8
     */
    @Before(&quot;webRequestLog()&quot;)
    public void doBefore(JoinPoint joinPoint){
        //获取UUID标识
        String REQUEST_UUID = java.util.UUID.randomUUID().toString().replaceAll(&quot;-&quot;, &quot;&quot;).toUpperCase();
        requestUUID.set(REQUEST_UUID);
        startTime.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        request.setAttribute(&quot;REQUEST_UUID&quot;, REQUEST_UUID);
        StringBuffer sbStr = new StringBuffer(&quot;ClentRequestInfoStar===REQUEST_UUID:&quot;)
                .append(REQUEST_UUID).append(&quot;,URL:&quot;)//监控参数
                .append(request.getRequestURL()).append(&quot;,&quot;)
                .append(&quot;HTTP_TYPE:&quot;).append(request.getMethod()).append(&quot;,&quot;)
                .append(&quot;CLASS_METHOD:&quot;).append(joinPoint.getSignature().getName()).append(&quot;,&quot;)
                .append(&quot;CLIENT_IP:&quot;).append(IPUtils.getClientIpAddress(request)).append(&quot;,&quot;)
                .append(&quot;PARAMS:&quot;);
        Enumeration&lt;String&gt; enu=request.getParameterNames(); 
        while(enu.hasMoreElements()){
            String elementType = enu.nextElement();
            sbStr.append(elementType).append(&quot;=&quot;).append(request.getParameter(elementType)).append(&quot;&amp;&quot;); 
        }
        logger.info(sbStr.deleteCharAt(sbStr.length()-1).toString());
    }

    @AfterReturning(returning = &quot;result&quot;, pointcut = &quot;webRequestLog()&quot;)
    public void doAfterReturning(Object result) {
        StringBuffer sbStr = new StringBuffer(&quot;ClentRequestInfoEnd===REQUEST_UUID:&quot;)
                .append(requestUUID.get()).append(&quot;,REQUEST_TIME:&quot;+(System.currentTimeMillis()-startTime.get())).append(&quot;ms&quot;);
        logger.info(sbStr.toString());
    }
}
</code></pre><p>我测试了一下，我们上面整合完后的日志打印情况，注意日志里面的REQUEST_UUID，这个就是一个请求串，我们只需要找REQUEST_UUID这个对应的开始于结束之间的日志内容就可以看出问题了哦。</p>
<pre><code>192.168.135.1:LAPTOP-796KKEL9:10:38:11.667 [http-nio-8080-exec-1] INFO  j.p.f.logback.WebRequestLogRecording -- ClentRequestInfoStar===REQUEST_UUID:1E3B70307FB443B4A5710382F2B8C225,URL:http://localhost:8080/api/investment/fsdt/baseTypeController/getBaseTypeByKey,HTTP_TYPE:GET,CLASS_METHOD:getBaseTypeByKey,CLIENT_IP:0:0:0:0:0:0:0:1,PARAMS:dtbaseid=char

&gt;&gt;&gt;&gt;1212066477842432
819010491752910848
819010493019590656
819010494290464768
819010495569727488
819010496840601600
没有缓存的时候，进入方法进行查询啦
192.168.135.1:LAPTOP-796KKEL9:10:38:13.657 [http-nio-8080-exec-1] ERROR c.g.i.i.c.InvestBaseTypeController -- 1E3B70307FB443B4A5710382F2B8C225**********查询条件不能为空

192.168.135.1:LAPTOP-796KKEL9:10:38:14.007 [http-nio-8080-exec-1] ERROR c.g.i.i.c.InvestBaseTypeController -- &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;2

192.168.135.1:LAPTOP-796KKEL9:10:38:14.020 [http-nio-8080-exec-1] INFO  j.p.f.logback.WebRequestLogRecording -- ClentRequestInfoEnd===REQUEST_UUID:1E3B70307FB443B4A5710382F2B8C225,REQUEST_TIME:2395ms
</code></pre>
                
<p class="red-link-context">
    <a href="/2017/07/28/Tomcat7+ Linux系统中启动慢解决方法/" rel="next" title="Tomcat7+ Linux系统中启动慢解决方法">
    上一篇：Tomcat7+ Linux系统中启动慢解决方法
  </a>
</p>



<p class="red-link-context">
    <a href="/2017/07/06/SpringBoot中的日志配置，多环境日志配置/" rel="next" title="SpringBoot中的日志配置，多环境日志配置">
    下一篇：SpringBoot中的日志配置，多环境日志配置
  </a>
</p>


            </div>
			
        </div>
    </div>
</article>




    <section id="comment">
        <div class="card">
            <div class="card-content">
                <!-- Duoshuo Comment BEGIN -->
                <div class="ds-thread" data-thread-key="2017/07/06/SpringBoot系统日志设计及实现方案/" data-title="SpringBoot系统日志设计及实现方案" data-url="http://dengzy007hi.oschina.io/2017/07/06/SpringBoot系统日志设计及实现方案/"></div>

                <script type="text/javascript">
                    console.log(document.querySelector('.ds-thread'));
                    var duoshuoQuery = {
                        short_name: 'dengzy007hi'
                    };
                    (function() {
                        var ds = document.createElement('script');
                        ds.type = 'text/javascript';
                        ds.async = true;
                        ds.src = (document.location.protocol == 'https:'
                            ? 'https:'
                            : 'http:') + '//static.duoshuo.com/embed.js';
                        ds.charset = 'UTF-8';
                        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
                    })();
                </script>
                <!-- Duoshuo Comment END -->
            </div>
        </div>
    </section>



</div>

        <div class="fixed-action-btn float-sitemap">
    <a class="btn-floating btn-large red">
      <i class="fa fa-caret-square-o-up"></i>
    </a>
    <ul>
      <li><a class="btn-return-top btn-floating waves-effect cyan" title="回到顶部"><i class="fa fa-arrow-circle-o-up"></i></a></li>
      <li><a class="btn-floating waves-effect button-collapse light-green"  data-activates="main-menu" title="menu"><i class="fa fa-navicon"></i></a></li>
    </ul>
  </div>

    </main>
    <footer class="page-footer green darken-1">
    
    <div class="container">
        <div class="row">
            
            <div class="social-group col m4 s12">
                <h5 class="white-text">社交</h5>
                
                    <a class="social-link" href="http://weibo.com/bambooJN" target="_blank">
                        <i class="fa fa-2x fa-weibo"></i>
                    </a>
                
                    <a class="social-link" href="https://git.oschina.net/dengzy007hi" target="_blank">
                        <i class="fa fa-2x fa-github"></i>
                    </a>
                
                    <a class="social-link" href="/atom.xml" target="_blank">
                        <i class="fa fa-2x fa-rss"></i>
                    </a>
                
                <div class="site-visitors-container white-text">
                    <span>
                        <i class="fa fa-user"></i>
                        <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
                    </span>
                    <span>&nbsp;|&nbsp;</span>
                    <span>
                        <i class="fa fa-eye"></i>
                        <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
                    </span>
                </div>
            </div>
            

            
            <div class="col m8 s12">
                <h5 class="white-text">友情链接</h5>
                
                    <a class="social-link" href="https://www.oschina.net" target="_blank">开源中国</a>
                
                    <a class="social-link" href="http://jdkleo.iteye.com/" target="_blank">JDKLEO</a>
                
                    <a class="social-link" href="http://pkaq.org/" target="_blank">如是我闻</a>
                
            </div>
            
        </div>
    </div>
    

    <div class="footer-copyright red-link-context">
        <div class="container">
            © 2017 dzy20@qq.com, All rights reserved.
            <p class="right" style="margin-top: 0;">本博客由 <a href="https://hexo.io">Hexo</a> 强力驱动 | 主题 <a href="https://github.com/raytaylorlin/hexo-theme-raytaylorism">raytaylorism</a></p>
        </div>
    </div>
</footer>


    <noscript>
    <div class="noscript">
        <p class="center-align">当前网速较慢或者你使用的浏览器不支持博客特定功能，请尝试刷新或换用Chrome、Firefox等现代浏览器</p>
    </div>
</noscript>
<div class="noscript">
    <p class="center-align">当前网速较慢或者你使用的浏览器不支持博客特定功能，请尝试刷新或换用Chrome、Firefox等现代浏览器</p>
</div>


<script src="/js/jquery.min.js"></script>
<script src="/js/materialize.min.js"></script>
<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js">
</script>

<script>
    (function($) {
        $(document).ready(function() {
            // 隐藏禁用javascript（针对微信内置浏览器）的提示
            $('.noscript').hide();

            // 图片缩放效果
            var $imgs = $('img').not('.slider-image').not('.avatar-image').not('.carousel-image').not('.card-cover-image').not('.qrcode');

            // 给图片加上点击放大效果（materialbox插件）
            $imgs.addClass('materialboxed').each(function(i, el) {
                $(this).attr('data-caption', $(this).attr('alt') || ' ');
            }).materialbox();

            // 优化表格的显示
            $('table').each(function() {
                var $table = $(this);
                // 除去多行代码的情况
                if ($table.find('pre').length == 0) {
                    $table.addClass('responsive-table striped bordered');
                }
            });

            // 首页幻灯片
            $('.slider').slider({indicators: true, full_width: true, interval: 8000});

            $(".button-collapse").sideNav();
            $(".category-menu").sideNav();

            // 针对gallery post
            $('.carousel').carousel({full_width: true});
            $('.carousel-control.prev').click(function() {
                $('.carousel').carousel('prev');
            });
            $('.carousel-control.next').click(function() {
                $('.carousel').carousel('next');
            });

            // 文章目录
            $('article').not('.simple-article').find('h1').add('h2').add('h3').add('h4').add('h5').add('h6').scrollSpy();

            // 目录随屏幕滚动（防止目录过长越过footer）
            var $toc = $('.toc');
            var scrollTargetTop = 0;
            $(window).scroll(function() {
                var $activeLink = $toc.find('a.active.section');
                if ($(window).scrollTop() < 100) {
                    scrollTargetTop = 0;
                } else {
                    if ($activeLink[0]) {
                        scrollTargetTop = $activeLink.offset().top - $toc.offset().top;
                    }
                }
                $toc.css('top', '-' + scrollTargetTop + 'px');
            });

            // 修正文章目录的left-border颜色
            var color = $('.table-of-contents-text').css('color');
            $('.table-of-contents-link').css('border-left-color', color);

            // 针对移动端做的优化：FAB按钮点击一下收回
            if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
                $('.fixed-action-btn').addClass('click-to-toggle');
            }
            // 回到顶部
            $('.btn-return-top').click(function() {
                $('body, html').animate({
                    scrollTop: 0
                }, 500);
            });

            // 重置读书页面的Tab标签页的颜色
            $('li.tab a').hover(function() {
                $(this).toggleClass('text-lighten-4');
            });
            $('.indicator').addClass('red lighten-2');

            
            // 添加new标签
            $('.menu-about').append('<span class="new badge red"></span>');
            

            // 搜索功能
            $('.modal-trigger').leanModal({
                // 打开搜索框时自动聚焦
                ready: function() {
                    if ($('#search').is(":visible")) {
                        $('#search-input').focus();
                    }
                }
            });
            var searchXml = "search.xml";
            if (searchXml.length == 0) {
             	searchXml = "search.xml";
            }
            var searchPath = "/" + searchXml;
            initSearch(searchPath, 'search-input', 'search-result');
        });

        // 初始化搜索与匹配函数
        var initSearch = function(path, search_id, content_id) {
            'use strict';
            $.ajax({
                url: path,
                dataType: "xml",
                success: function(xmlResponse) {
                    // get the contents from search data
                    var datas = $("entry", xmlResponse).map(function() {
                        return {
                            title: $("title", this).text(),
                            content: $("content", this).text(),
                            url: $("url", this).text()
                        };
                    }).get();
                    var $input = document.getElementById(search_id);
                    var $resultContent = document.getElementById(content_id);
                    $input.addEventListener('input', function() {
                        var str = '<ul class=\"search-result-list\">';
                        var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                        $resultContent.innerHTML = "";
                        if (this.value.trim().length <= 0) {
                            return;
                        }
                        // perform local searching
                        datas.forEach(function(data) {
                            var isMatch = true;
                            var content_index = [];
                            var data_title = data.title.trim().toLowerCase();
                            var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                            var data_url = data.url;
                            var index_title = -1;
                            var index_content = -1;
                            var first_occur = -1;
                            // only match artiles with not empty titles and contents
                            if (data_title != '' && data_content != '') {
                                keywords.forEach(function(keyword, i) {
                                    index_title = data_title.indexOf(keyword);
                                    index_content = data_content.indexOf(keyword);
                                    if (index_title < 0 && index_content < 0) {
                                        isMatch = false;
                                    } else {
                                        if (index_content < 0) {
                                            index_content = 0;
                                        }
                                        if (i == 0) {
                                            first_occur = index_content;
                                        }
                                    }
                                });
                            }
                            // show search results
                            if (isMatch) {
                                keywords.forEach(function(keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    data_title = data_title.replace(regS, "<span class=\"search-keyword red lighten-2\">" + keyword + "</span>");
                                });

                                str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                                var content = data.content.trim().replace(/<[^>]+>/g, "");
                                if (first_occur >= 0) {
                                    // cut out 100 characters
                                    var start = first_occur - 20;
                                    var end = first_occur + 80;
                                    if (start < 0) {
                                        start = 0;
                                    }
                                    if (start == 0) {
                                        end = 100;
                                    }
                                    if (end > content.length) {
                                        end = content.length;
                                    }
                                    var match_content = content.substring(start, end);
                                    // highlight all keywords
                                    keywords.forEach(function(keyword) {
                                        var regS = new RegExp(keyword, "gi");
                                        match_content = match_content.replace(regS, "<span class=\"search-keyword red lighten-2\">" + keyword + "</span>");
                                    });

                                    str += "<p class=\"search-result\">..." + match_content + "...</p>"
                                }
                                str += "</li>";
                            }
                        });
                        str += "</ul>";
                        $resultContent.innerHTML = str;
                    });
                }
            });
        }
    })(jQuery);
</script>


<script src="/js/prettify.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        $("pre").addClass("prettyprint");
        prettyPrint();
    });
</script>








</body>
</html>
